/*
 * Copyright (C) 2008-2012  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

#include "exl.h"

/*
 * Initialization
 */
efunction_t		*root_function;
efunction_t		*current_function;
ehash_t			*function_table;

/*
 * Implementation
 */
void
init_function(void)
{
    esymbol_t		*symbol;
    eobject_t		*pointer;

    eadd_root((eobject_t *)&function_table);
    enew_hash((eobject_t *)&function_table, 16);

    gc_ref(pointer);
    enew_object(pointer, t_function, sizeof(efunction_t));
    root_function = *pointer;

    /* empty string symbol identifier */
    root_function->name = eget_string((euint8_t *)"", 0);
    symbol = enew_identifier(root_function->name);
    enew_value((eobject_t *)&root_function->value, symbol, 0);
    root_function->namespace = enew_namespace(symbol, null);

    eput_hash(function_table, (eentry_t *)root_function);
    gc_dec();
    enew_hash((eobject_t *)&root_function->value->hash, 8);
    enew_hash((eobject_t *)&root_function->label_table, 8);
    enew_vector((eobject_t *)&root_function->value_vector, t_void, 8);

    symbol->value = root_function;
    current_function = root_function;

    /* setup ast node information for root function */
    enew_ast((eobject_t *)&root_function->ast,
	     tok_function, symbol->name, 0, 0);
    enew_ast(&root_function->ast->l.value, tok_type, symbol->name, 0, 0);
    root_function->ast->l.ast->l.value = etag_object(type_vector->v.ptr[0]);
    enew_ast(&root_function->ast->r.value, tok_proto, symbol->name, 0, 0);
    enew_ast(&root_function->ast->r.ast->l.value,
	     tok_symbol, symbol->name, 0, 0);
    root_function->ast->r.ast->l.ast->l.value = symbol;
    enew_ast(&root_function->ast->c.value, tok_code, symbol->name, 0, 0);
    root_function->ast->t.value = root_function;
}

void
finish_function(void)
{
    erem_root((eobject_t *)&function_table);
}

efunction_t *
eget_function(evector_t *name)
{
    return ((efunction_t *)eget_hash(function_table, name));
}

efunction_t *
enew_function(evector_t *name, etag_t *tag)
{
    esymbol_t		*symbol;
    eobject_t		*pointer;
    efunction_t		*function;

    assert(tag->type == tag_function);

    gc_ref(pointer);
    enew_object(pointer, t_function, sizeof(efunction_t));
    function = *pointer;

    /* Possible prototype will have created symbol */
    function->name = name;
    if ((symbol = eget_symbol(current_namespace, name)))
	assert(symbol->tag == tag);
    else
	symbol = enew_symbol(current_namespace, name, tag);
    enew_value((eobject_t *)&function->value, symbol, function_table->count);
    function->namespace = enew_namespace(symbol, current_namespace);

    function->tag = tag;
    eput_hash(function_table, (eentry_t *)function);
    gc_dec();
    enew_hash((eobject_t *)&function->value->hash, 8);
    enew_hash((eobject_t *)&function->label_table, 8);
    enew_vector((eobject_t *)&function->value_vector, t_void, 8);

    symbol->value = function;

    return (function);
}
